package org.jdns.jfreechess.server;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.io.Resources;
import com.google.inject.Guice;

import org.jdns.jfreechess.server.commands.QuitCommand;
import org.jdns.jfreechess.server.commands.TellCommand;
import org.jdns.jfreechess.server.commands.WhoCommand;

import io.netty.bootstrap.ServerBootstrap;

import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

import javax.inject.Inject;

public class ChessServer {

  private final ServerBootstrap bootstrap;
  private final Map<String, User> users = Collections.synchronizedMap(Maps
      .<String, User> newHashMap());
  private final Logger logger;

  public static void main(String[] args) {
    try {
      LogManager.getLogManager().readConfiguration(
          Resources.getResource("logging.properties").openStream());
    } catch (IllegalArgumentException e) {
      System.err.println(
          "Could not find logging configuration, will proceed with default configuration");
      e.printStackTrace();
    } catch (IOException e) {
      System.err.println(
          "Could not read logging configuration, will proceed with default configuration");
      e.printStackTrace();
    }

    ChessServer server = Guice.createInjector(new ChessServerServingModule() {
      @Override
      protected void configureChessServer() {
        addCommand(TellCommand.class);
        addCommand(QuitCommand.class);
        addCommand(WhoCommand.class);
      }
    }).getInstance(ChessServer.class);
    server.start();
  }

  @Inject
  ChessServer(ServerBootstrap b, Logger logger) {
    this.bootstrap = b;
    this.logger = logger;
  }

  public void start() {
    logger.log(Level.INFO, "Listening on port 5000");
    bootstrap.bind();
  }

  public void userConnected(User user) {
    users.put(user.getName().toLowerCase(), user);
  }

  public User getUser(String name) {
    return users.get(name);
  }

  public void userDisconnected(User user) {
    users.remove(user.getName());
  }

  /**
   * Returns an immutable copy of the list of currently connected users.
   */
  public Set<User> getConnectedUsers() {
    return ImmutableSet.<User> copyOf(users.values());
  }

  /**
   * Returns an immutable copy of the map of currently connected users by username.
   */
  public Map<String, User> getConnectedUsersByName() {
    return ImmutableMap.copyOf(users);
  }

}
